
#include "core/dest_cache.h"
#include "core/service.h"
#include "core/core_message.h"
#include "x_endian.h"
#include "config.h"

void DestCache::Init(void) {
  module_handle_ = Services::Instance().New(NULL, "cache", NULL);
}

void DestCache::UpdateRecord(const char* raw_list) {
  boost::mutex::scoped_lock l(cache_mutex_);
  uint16_t list_size = be16toh(*((const uint16_t*)(raw_list)));
  raw_list += 2;
  for (uint16_t i = 0; i < list_size; i++) {
    uint16_t is_add = be16toh(*((const uint16_t*)(raw_list)));
    uint16_t key_size = be16toh(*((const uint16_t*)(raw_list + 2)));
    std::string key(raw_list + 4, key_size);
    raw_list += (4 + key_size);
    if (is_add) {
      uint16_t val_size = be16toh(*((const uint16_t*)(raw_list)));
      std::string val(raw_list + 2, val_size);
      raw_list += (2 + val_size);
      cache_[key] = val;
    } else {
      cache_.erase(key);
    }
  }
}

void DestCache::UpdateRecord(uint16_t is_add, const char* key, 
                             const char* val) {
  boost::mutex::scoped_lock l(cache_mutex_);
  if (is_add) 
    cache_[key] = val;
  else
    cache_.erase(key);
}

void DestCache::RegisterService(const std::string& name, Handle handle) {
  if (name.front() == ':') return;
  if (name.front() == '.') {
    boost::mutex::scoped_lock l(local_services_mutex_);
    local_services_[name] = handle;
  } else {
    uint16_t len = 2 + 2 + name.size() + 4;
    char* data = new char[len];
    *(uint16_t*)(&data[0]) = htobe16(1);
    *(uint16_t*)(&data[1]) = htobe16(name.size());
    memcpy(&data[3], name.c_str(), name.size());
    *(uint32_t*)(&data[3 + name.size()]) = htobe32(handle.value());
    CoreMessage msg;
    BOOST_ASSERT(create_message(NULL, -1, true, kLogic, data, len, &msg));
    Services::Instance().Send(module_handle_, msg);

    boost::mutex::scoped_lock l(cache_mutex_);
    cache_[name] = boost::lexical_cast<std::string>(handle.value());
  }
}

void DestCache::RetireService(const std::string& name) {
  if (name.front() == ':') return;
  if (name.front() == '.') {
    boost::mutex::scoped_lock l(local_services_mutex_);
    local_services_.erase(name);
  } else {
    uint16_t len = 2 + 2 + name.size();
    char* data = new char[len];
    *(uint16_t*)(&data[0]) = 0; // remove record msg id
    *(uint16_t*)(&data[1]) = htobe16(name.size()); // name len
    memcpy(&data[3], name.c_str(), name.size()); // name
    CoreMessage msg;
    BOOST_ASSERT(create_message(NULL, -1, true, kLogic, data, len, &msg));
    Services::Instance().Send(module_handle_, msg);
    
    boost::mutex::scoped_lock l(cache_mutex_);
    cache_.erase(name);
  }
}

Handle DestCache::Query(const std::string& name) {
  if (name.empty()) return Handle::kInvalid;
  if (name.front() == ':') {
    return Handle(boost::lexical_cast<uint32_t>(name.c_str() + 1));
  } else if (name.front() == '.') {
    boost::mutex::scoped_lock l(local_services_mutex_);
    auto it = local_services_.find(name);
    return it == local_services_.end() ? Handle::kInvalid : (*it).second;
  } else {
    boost::mutex::scoped_lock l(cache_mutex_);
    auto it = cache_.find(name); 
    if (it != cache_.end()) 
      return Handle(boost::lexical_cast<uint32_t>((*it).second));
    return Handle::kInvalid;
  }
}

std::string DestCache::Query(uint32_t svr_id) {
  boost::mutex::scoped_lock l(cache_mutex_);
  auto it = cache_.find(boost::lexical_cast<std::string>(svr_id));
  if (it != cache_.end())
    return (*it).second;
  return "";
}

